
import cn.hutool.core.collection.CollectionUtil;
import com.google.common.net.HttpHeaders;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.*;

/**
 * Word文档处理工具类，用于生成带有动态数据的Word报告
 * 支持普通占位符替换、动态段落和动态表格处理，并保留文档样式
 */
@Component
@Slf4j
public class WordUtils {

    // 占位符模式定义
    private static final Pattern DATA_ROW_PATTERN = Pattern.compile("\\$\\{(row|plant)\\.[^}]+}");
    private static final Pattern TABLE_START_PATTERN = Pattern.compile("\\$\\{table:(\\w+):start}");
    private static final Pattern TABLE_END_PATTERN = Pattern.compile("\\$\\{table:(\\w+):end}");
    private static final Pattern PARAGRAPH_START_PATTERN = Pattern.compile("\\$\\{paragraph:(\\w+):start}");
    private static final Pattern PARAGRAPH_END_PATTERN = Pattern.compile("\\$\\{paragraph:(\\w+):end}");

    // 高亮样式关键字
    private static final Set<String> STYLE_KEYS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
            "invMaintainCount", "invFaultCount", "fault", "maintain")));

    /**
     * 生成Word报告
     *
     * @param templatePath   模板路径
     * @param response       HTTP响应
     * @param simpleDataMap  普通数据映射
     * @param tableDataMap   表格数据映射
     * @param stationDataMap 场站数据映射
     */
    public static void generateReport(String templatePath,
                                      HttpServletResponse response,
                                      Map<String, String> simpleDataMap,
                                      Map<String, List<Map<String, String>>> tableDataMap,
                                      Map<String, Map<String, List<Map<String, String>>>> stationDataMap) {

        try (InputStream templateInputStream = Files.newInputStream(Paths.get(templatePath));
             XWPFDocument doc = new XWPFDocument(templateInputStream)) {

            // 1. 替换普通占位符
            replaceSimplePlaceholders(doc, simpleDataMap);

            // 2. 处理动态段落
            processDynamicParagraphs(doc, tableDataMap);

            // 3. 处理动态表格
            processDynamicTables(doc, tableDataMap, stationDataMap);

            insertAttachmentsPageBreaks(doc);

            // 设置响应头
            response.setContentType("application/octet-stream");
            String encodedFilename = URLEncoder.encode("新能源调度日报.docx", StandardCharsets.UTF_8.toString());
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + encodedFilename);

            // 保存生成的报告
            try (OutputStream os = response.getOutputStream()) {
                doc.write(os);
            }
        } catch (IOException e) {
            log.error("导出Word文件时发生异常：", e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 替换文档中的普通占位符
     *
     * @param doc           Word文档
     * @param simpleDataMap 数据映射
     */
    private static void replaceSimplePlaceholders(XWPFDocument doc, Map<String, String> simpleDataMap) {
        // 处理段落中的占位符
        parseAllParagraph(doc.getParagraphs(), simpleDataMap);

        // 处理表格中的占位符
        for (XWPFTable table : doc.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    parseAllParagraph(cell.getParagraphs(), simpleDataMap);
                }
            }
        }

        // 处理页眉页脚
        for (XWPFHeader header : doc.getHeaderList()) {
            parseAllParagraph(header.getParagraphs(), simpleDataMap);
        }

        for (XWPFFooter footer : doc.getFooterList()) {
            parseAllParagraph(footer.getParagraphs(), simpleDataMap);
        }
    }

    /**
     * 处理所有段落中的占位符
     */
    private static void parseAllParagraph(List<XWPFParagraph> paragraphs, Map<String, String> simpleDataMap) {
        for (XWPFParagraph paragraph : paragraphs) {
            if (paragraph.getText() != null && paragraph.getText().contains("${")) {
                parseThisParagraph(paragraph, simpleDataMap, false);
            }
        }
    }

    /**
     * 处理单个段落中的占位符
     */
    private static void parseThisParagraph(XWPFParagraph paragraph, Map<String, String> data, boolean skipDynamicTagCheck) {
        XWPFRun currentRun = null;
        String currentText = "";
        boolean isFinding = false;
        List<Integer> runIndex = new ArrayList<>();

        for (int i = 0; i < paragraph.getRuns().size(); i++) {
            XWPFRun run = paragraph.getRuns().get(i);
            String text = run.getText(0);

            if (StringUtils.isNotEmpty(text)) {
                if (isFinding) {
                    currentText += text;

                    if (!currentText.contains("${")) {
                        isFinding = false;
                        runIndex.clear();
                    } else {
                        runIndex.add(i);
                    }

                    if (currentText.contains("}")) {
                        changeValues(paragraph, currentRun, currentText, runIndex, data, skipDynamicTagCheck);
                        currentText = "";
                        isFinding = false;
                    }
                } else if (text.contains("${")) {
                    currentText = text;
                    isFinding = true;
                    currentRun = run;
                } else {
                    currentText = "";
                }

                if (currentText.contains("}")) {
                    changeValues(paragraph, currentRun, currentText, runIndex, data, skipDynamicTagCheck);
                    isFinding = false;
                }
            }
        }
    }

    /**
     * 替换占位符的值（新增flag参数）
     */
    private static void changeValues(XWPFParagraph paragraph, XWPFRun currentRun, String currentText,
                                     List<Integer> runIndex, Map<String, String> data, boolean skipDynamicTagCheck) {
        // 根据flag决定是否跳过动态标签检查
        if (!skipDynamicTagCheck && isDynamicTag(currentText)) {
            return;
        }

        // 提取占位符 key
        currentText = currentText.replace("${", "").replace("}", "");
        String[] keys = currentText.split("\\s+");

        // 使用数据映射获取值
        String value = "{" + currentText + "}";
        if (keys.length > 0) {
            value = data.getOrDefault(keys[0], "{" + currentText + "}");
        }

        boolean shouldHighlight = checkShouldHighlight(data, currentText);

        // 应用值到当前Run并保留样式
        applyValueWithStyle(currentRun, value, shouldHighlight);

        // 清空其他相关Run的内容
        for (int index : runIndex) {
            paragraph.getRuns().get(index).setText("", 0);
        }
        runIndex.clear();
    }

    /**
     * 应用值并保留样式
     */
    private static void applyValueWithStyle(XWPFRun run, String value, boolean shouldHighlight) {
        // 先保存原有样式
        CTRPr originalStyle = run.getCTR().isSetRPr() ? (CTRPr) run.getCTR().getRPr().copy() : null;

        // 设置新文本
        run.setText(value, 0);

        // 恢复原有样式
        if (originalStyle != null) {
            run.getCTR().setRPr(originalStyle);
            if (shouldHighlight) {
                run.setColor("FF0000");
            }
        }
    }


    /**
     * 处理动态段落
     */
    private static void processDynamicParagraphs(XWPFDocument doc, Map<String, List<Map<String, String>>> paragraphDataMap) {
        List<IBodyElement> bodyElements = doc.getBodyElements();
        int i = 0;
        while (i < bodyElements.size()) {
            IBodyElement element = bodyElements.get(i);
            if (element instanceof XWPFParagraph) {
                XWPFParagraph p = (XWPFParagraph) element;
                String text = p.getText();
                if (text == null) {
                    i++;
                    continue;
                }

                Matcher startMatcher = PARAGRAPH_START_PATTERN.matcher(text);
                if (startMatcher.find()) {
                    String paraName = startMatcher.group(1);
                    int endIndex = -1;

                    // 查找结束标记
                    for (int j = i + 1; j < bodyElements.size(); j++) {
                        IBodyElement endElement = bodyElements.get(j);
                        if (endElement instanceof XWPFParagraph) {
                            XWPFParagraph endPara = (XWPFParagraph) endElement;
                            String endText = endPara.getText();
                            if (endText != null) {
                                Matcher endMatcher = PARAGRAPH_END_PATTERN.matcher(endText);
                                if (endMatcher.find() && paraName.equals(endMatcher.group(1))) {
                                    endIndex = j;
                                    break;
                                }
                            }
                        }
                    }

                    if (endIndex > i) {
                        // 获取模板段落（开始标记的下一个段落）
                        if (i + 1 >= bodyElements.size() || !(bodyElements.get(i + 1) instanceof XWPFParagraph)) {
                            i++;
                            continue;
                        }

                        XWPFParagraph templatePara = (XWPFParagraph) bodyElements.get(i + 1);
                        // 保存模板Run结构（包含段落样式）
                        List<RunStructure> runStructures = new ArrayList<>();
                        for (XWPFRun run : templatePara.getRuns()) {
                            runStructures.add(new RunStructure(run, templatePara));
                        }


                        // 获取数据
                        List<Map<String, String>> dataList = paragraphDataMap.get(paraName);
                        if (dataList == null || dataList.isEmpty()) {
                            // 删除整个区域（从后往前删）
                            doc.removeBodyElement(endIndex); // 结束标记
                            doc.removeBodyElement(i + 1);  // 模板
                            doc.removeBodyElement(i);       // 开始标记
                            bodyElements = doc.getBodyElements();
                            continue;
                        }

                        // ==== 1. 删除标记段落 ====
                        // 先记录要删除的段落索引
                        int startMarkerIndex = i;
                        int templateIndex = i + 1;

                        // 从后往前删除避免索引变化
                        doc.removeBodyElement(endIndex);
                        doc.removeBodyElement(templateIndex);
                        doc.removeBodyElement(startMarkerIndex);

                        // ==== 2. 插入数据段落 ====
                        int insertPos = startMarkerIndex; // 在原来开始标记的位置插入
                        for (Map<String, String> data : dataList) {
                            // 创建新段落
                            XmlCursor cursor = createInsertCursor(doc, insertPos);
                            XWPFParagraph newPara = doc.insertNewParagraph(cursor);

                            // 重建Run结构并应用样式
                            for (RunStructure structure : runStructures) {
                                structure.applyToRun(newPara);
                            }

                            // 处理占位符（跳过动态标签检查）
                            parseThisParagraph(newPara, data, true);
                            insertPos++;
                        }

                        // 重置扫描
                        bodyElements = doc.getBodyElements();
                        i = 0;
                        continue;
                    }
                }
            }
            i++;
        }
    }

    /**
     * 处理动态表格
     */
    private static void processDynamicTables(XWPFDocument doc, Map<String, List<Map<String, String>>> tableDataMap,
                                             Map<String, Map<String, List<Map<String, String>>>> stationDataMap) {
        // 查找所有表格
        for (int i = 0; i < doc.getBodyElements().size(); i++) {
            IBodyElement element = doc.getBodyElements().get(i);
            if (element instanceof XWPFParagraph) {
                XWPFParagraph para = (XWPFParagraph) element;
                String text = para.getText();

                // 检查表格开始标记
                Matcher startMatcher = TABLE_START_PATTERN.matcher(text);
                if (startMatcher.find()) {
                    String tableName = startMatcher.group(1);

                    // 查找结束标记
                    int endIndex = findTableEndIndex(doc, i + 1, tableName);
                    if (endIndex > i) {
                        // 删除开始和结束标记段落
                        doc.removeBodyElement(i);
                        doc.removeBodyElement(endIndex - 1);

                        // 处理表格区域
                        processTableRegion(doc, i, endIndex - 1, tableName, tableDataMap, stationDataMap);
                        i = endIndex - 1; // 调整索引
                    }
                }
            }
        }
    }

    /**
     * 处理表格区域
     */
    private static void processTableRegion(XWPFDocument doc, int startIndex, int endIndex,
                                           String tableName, Map<String, List<Map<String, String>>> tableDataMap,
                                           Map<String, Map<String, List<Map<String, String>>>> stationDataMap) {
        // 查找模板行
        XWPFTable templateTable = null;
        int templateRowIndex = -1;

        for (int i = startIndex; i <= endIndex; i++) {
            IBodyElement element = doc.getBodyElements().get(i);
            if (element instanceof XWPFTable) {
                XWPFTable table = (XWPFTable) element;
                for (int j = 0; j < table.getRows().size(); j++) {
                    XWPFTableRow row = table.getRows().get(j);
                    if (isTemplateRow(row)) {
                        templateTable = table;
                        templateRowIndex = j;
                        break;
                    }
                }
            }
        }

        if (templateTable != null) {
            // 处理附件2分组表格
            if (tableName.startsWith("group_")) {
                processGroupInvDetailsTable(tableName, templateTable, tableDataMap, stationDataMap);
            } else {
                // 处理普通表格
                processNormalTable(templateTable, templateRowIndex, tableName, tableDataMap);
            }
        }
    }

    /**
     * 处理普通表格
     */
    private static void processNormalTable(XWPFTable table, int templateRowIndex, String tableName,
                                           Map<String, List<Map<String, String>>> tableDataMap) {
        List<Map<String, String>> tableData = tableDataMap.get(tableName);
        if (tableData == null) return;

        try {
            XWPFTableRow templateRow = table.getRow(templateRowIndex);
            List<TableColumnParam> paramsList = parseTemplateRow(templateRow);

            for (Map<String, String> rowData : tableData) {
                XWPFTableRow newRow = table.insertNewTableRow(templateRowIndex);
                copyRowFormatting(templateRow, newRow);
                fillRowWithData(newRow, paramsList, rowData);

                templateRowIndex++;
            }

            table.removeRow(templateRowIndex);
        } catch (Exception e) {
            log.error("填充普通表格时出错", e);
        }
    }


    /**
     * 处理分组表格
     */
    private static void processGroupInvDetailsTable(String tableName, XWPFTable table,
                                                    Map<String, List<Map<String, String>>> tableDataMap,
                                                    Map<String, Map<String, List<Map<String, String>>>> stationDataMap) {
        try {
            // 定位模板行
            XWPFTableRow stationDataTemplateRow = null;
            XWPFTableRow plantTotalTemplateRow = null;
            XWPFTableRow plantNameTemplateRow = null;

            // 假设模板行位置（根据实际情况调整）
            if (table.getRows().size() > 4) {
                stationDataTemplateRow = table.getRow(4); // 第4行是场站数据模板
                plantTotalTemplateRow = table.getRow(5); // 第5行是电厂总计模板
                plantNameTemplateRow = table.getRow(3);   // 第3行是分组标题模板
            }
            // 获取数据
            String[] dataKeys = tableName.split("_");
            String dataKey = dataKeys[1];
            List<Map<String, String>> plantGroups = tableDataMap.get(dataKey);
            Map<String, List<Map<String, String>>> groupedResult = stationDataMap.get(dataKey);
            if (plantGroups == null || plantGroups.isEmpty()) return;


            List<TableColumnParam> plantNameParams = parseTemplateRow(plantNameTemplateRow);
            List<TableColumnParam> stationDataParams = parseTemplateRow(stationDataTemplateRow);
            List<TableColumnParam> plantTotalParams = parseTemplateRow(plantTotalTemplateRow);


            // 填充分组数据
            int insertPosition = 3; // 从第3行开始插入

            for (int i = 0; i < plantGroups.size(); i++) {
                Map<String, String> plantGroup = plantGroups.get(i);
                String companyCode = plantGroup.get("companyCode");
                List<Map<String, String>> stations = groupedResult.get(companyCode);
                if (CollectionUtil.isNotEmpty(stations)) {


                    // 添加分组标题行
                    if (plantNameTemplateRow != null) {
                        XWPFTableRow plantNameRow = table.insertNewTableRow(insertPosition);
                        copyRowFormatting(plantNameTemplateRow, plantNameRow);

                        Map<String, String> plantNameData = new HashMap<>();
                        plantNameData.put("plant.plantName", (i + 1) + "." + plantGroup.get("plant.plantName"));
                        fillRowWithData(plantNameRow, plantNameParams, plantNameData);

                        insertPosition++;
                    }

                    // 添加场站数据行
                    if (stationDataTemplateRow != null) {
                        for (int j = 0; j < stations.size(); j++) {
                            Map<String, String> station = stations.get(j);
                            station.put("row.index", String.valueOf(j + 1));

                            XWPFTableRow stationRow = table.insertNewTableRow(insertPosition);
                            copyRowFormatting(stationDataTemplateRow, stationRow);
                            fillRowWithData(stationRow, stationDataParams, station);
                            insertPosition++;
                        }
                    }
                    // 添加电厂总计行
                    if (plantTotalTemplateRow != null) {
                        XWPFTableRow plantTotalRow = table.insertNewTableRow(insertPosition);
                        copyRowFormatting(plantTotalTemplateRow, plantTotalRow);
                        plantGroup.put("plant.plantTotal", plantGroup.get("plant.plantName") + "总计");
                        fillRowWithData(plantTotalRow, plantTotalParams, plantGroup);

                        insertPosition++;
                    }
                }
            }
            int rowCount = table.getNumberOfRows();
            int rowsToRemove = Math.min(3, rowCount); // 防止行数不足三行

            for (int i = 0; i < rowsToRemove; i++) {
                table.removeRow(rowCount - 1 - i);
            }
        } catch (Exception e) {
            log.error("填充分组表格时出错", e);
        }
    }

    /**
     * 解析模板行，提取列参数
     */
    private static List<TableColumnParam> parseTemplateRow(XWPFTableRow templateRow) {
        List<TableColumnParam> paramsList = new ArrayList<>();
        if (templateRow == null) return paramsList;

        for (XWPFTableCell cell : templateRow.getTableCells()) {
            String text = cell.getText();
            String paramName = text != null ? text.trim().replace("${", "").replace("}", "") : "";

            int colspan = 1;
            if (cell.getCTTc().getTcPr() != null &&
                    cell.getCTTc().getTcPr().getGridSpan() != null &&
                    cell.getCTTc().getTcPr().getGridSpan().getVal() != null) {
                colspan = cell.getCTTc().getTcPr().getGridSpan().getVal().intValue();
            }

            paramsList.add(new TableColumnParam(paramName, colspan));
        }

        return paramsList;
    }

    /**
     * 复制行格式
     */
    private static void copyRowFormatting(XWPFTableRow source, XWPFTableRow target) {
        if (source == null) return;

        // 复制行属性
        if (source.getCtRow().getTrPr() != null) {
            target.getCtRow().setTrPr((CTTrPr) source.getCtRow().getTrPr().copy());
        }

        // 复制单元格格式
        for (int i = 0; i < source.getTableCells().size(); i++) {
            XWPFTableCell sourceCell = source.getTableCells().get(i);
            XWPFTableCell targetCell = i < target.getTableCells().size()
                    ? target.getTableCells().get(i)
                    : target.addNewTableCell();

            // 复制单元格属性
            if (sourceCell.getCTTc().getTcPr() != null) {
                targetCell.getCTTc().setTcPr((CTTcPr) sourceCell.getCTTc().getTcPr().copy());
            }

            // 复制单元格结构
            copyCellStructure(sourceCell, targetCell);
        }
    }

    /**
     * 复制单元格结构
     */
    private static void copyCellStructure(XWPFTableCell sourceCell, XWPFTableCell targetCell) {
        // 清空目标单元格
        while (!targetCell.getParagraphs().isEmpty()) {
            targetCell.removeParagraph(0);
        }

        // 复制段落结构
        for (XWPFParagraph sourcePara : sourceCell.getParagraphs()) {
            XWPFParagraph targetPara = targetCell.addParagraph();

            // 复制段落样式
            if (sourcePara.getCTP().isSetPPr()) {
                targetPara.getCTP().setPPr((CTPPr) sourcePara.getCTP().getPPr().copy());
            }

            // 复制Run结构
            for (XWPFRun sourceRun : sourcePara.getRuns()) {
                XWPFRun targetRun = targetPara.createRun();

                // 复制Run样式
                if (sourceRun.getCTR().isSetRPr()) {
                    targetRun.getCTR().setRPr((CTRPr) sourceRun.getCTR().getRPr().copy());
                }

                // 清空文本，但保留Run
                targetRun.setText("");
            }
        }
    }

    /**
     * 用数据填充行
     */
    private static void fillRowWithData(XWPFTableRow row, List<TableColumnParam> paramsList, Map<String, String> rowData) {
        if (row == null || paramsList.isEmpty()) return;

        List<XWPFTableCell> cells = row.getTableCells();
        int cellIndex = 0;
        int originalCellCount = cells.size();

        for (TableColumnParam param : paramsList) {
            String text = param.name;
            String value = rowData.getOrDefault(text, "");

            XWPFTableCell cell;
            if (cellIndex < originalCellCount) {
                cell = cells.get(cellIndex);
            } else {
                cell = row.addNewTableCell();
            }

            // 设置合并单元格
            if (param.colspan > 1) {
                cell.getCTTc().addNewTcPr().addNewGridSpan().setVal(BigInteger.valueOf(param.colspan));
            }
            replaceInRowApplyStyle(text, cell, rowData);
            // 填充数据到单元格
            fillCellWithData(cell, value);

            cellIndex += param.colspan;
            if (StringUtils.equals(param.name, "plant.plantTotal")) {
                cellIndex = cellIndex - 1;
            }
        }
    }

    /**
     * 用数据填充单元格
     */
    private static void fillCellWithData(XWPFTableCell cell, String value) {
        if (cell.getParagraphs().isEmpty()) {
            cell.addParagraph();
        }

        XWPFParagraph paragraph = cell.getParagraphs().get(0);

        if (paragraph.getRuns().isEmpty()) {
            XWPFRun run = paragraph.createRun();
            run.setText(value);
        } else {
            XWPFRun run = paragraph.getRuns().get(0);
            run.setText(value);
        }
    }

    /**
     * 判断是否为模板行
     */
    private static boolean isTemplateRow(XWPFTableRow row) {
        if (row == null) return false;

        for (XWPFTableCell cell : row.getTableCells()) {
            for (XWPFParagraph p : cell.getParagraphs()) {
                if (p.getText() != null && (p.getText().contains("${row.") || p.getText().contains("${plant."))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 应用行内样式
     */
    private static void replaceInRowApplyStyle(String text, XWPFTableCell tableCell, Map<String, String> data) {
        boolean shouldHighlight = false;
        String matchedKey = null;
        if (text != null) {
            for (String key : STYLE_KEYS) {
                String[] split = text.split("\\.");
                if (StringUtils.equals(key, split[1])) {
                    shouldHighlight = true;
                    matchedKey = text;
                    break;
                }
            }
        }

        if (shouldHighlight) {
            try {
                int value = Integer.parseInt(data.getOrDefault(matchedKey, "0"));
                if (value > 0) {
                    applyCellStyle(tableCell);
                }
            } catch (NumberFormatException ignored) {
                // 忽略非数字值
            }
        }
    }

    /**
     * 应用单元格样式
     */
    private static void applyCellStyle(XWPFTableCell cell) {
        if (cell == null || cell.getCTTc() == null) {
            return;
        }
        for (XWPFParagraph p : cell.getParagraphs()) {
            for (XWPFRun run : p.getRuns()) {
                run.setBold(true);
                run.setColor("FF0000");
            }
        }
    }

    /**
     * 查找表格结束标记
     */
    private static int findTableEndIndex(XWPFDocument doc, int startIndex, String tableName) {
        for (int i = startIndex; i < doc.getBodyElements().size(); i++) {
            IBodyElement element = doc.getBodyElements().get(i);
            if (element instanceof XWPFParagraph) {
                String text = ((XWPFParagraph) element).getText();
                Matcher endMatcher = TABLE_END_PATTERN.matcher(text);
                if (endMatcher.find() && tableName.equals(endMatcher.group(1))) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 检查是否需要高亮
     */
    private static boolean checkShouldHighlight(Map<String, String> data, String cellText) {
        for (String key : STYLE_KEYS) {
            if (StringUtils.equals(cellText, key)) {
                String valueStr = data.getOrDefault(key, "0");
                try {
                    int value = Integer.parseInt(valueStr);
                    return value > 0;
                } catch (NumberFormatException e) {
                    log.debug("无法解析数值用于样式应用: {}", valueStr);
                }
            }
        }
        return false;
    }

    /**
     * 创建插入游标
     */
    private static XmlCursor createInsertCursor(XWPFDocument doc, int insertPosition) {
        try {
            CTBody body = doc.getDocument().getBody();
            if (insertPosition >= doc.getBodyElements().size()) {
                return body.addNewP().newCursor();
            }

            IBodyElement element = doc.getBodyElements().get(insertPosition);
            if (element instanceof XWPFParagraph) {
                return ((XWPFParagraph) element).getCTP().newCursor();
            } else if (element instanceof XWPFTable) {
                return ((XWPFTable) element).getCTTbl().newCursor();
            }
        } catch (Exception e) {
            log.error("创建插入游标失败", e);
        }

        return doc.getDocument().getBody().addNewP().newCursor();
    }

    /**
     * 检查文本是否为动态标签
     */
    private static boolean isDynamicTag(String text) {
        return TABLE_START_PATTERN.matcher(text).find() ||
                TABLE_END_PATTERN.matcher(text).find() ||
                PARAGRAPH_START_PATTERN.matcher(text).find() ||
                PARAGRAPH_END_PATTERN.matcher(text).find() ||
                DATA_ROW_PATTERN.matcher(text).find();
    }

    /**
     * 保存Run结构的辅助类
     */
    /**
     * 保存Run结构的辅助类（增强样式保留）
     */
    private static class RunStructure {
        private final String text;
        private final CTRPr rPr;
        private final CTPPr pPr; // 新增段落样式

        public RunStructure(XWPFRun run, XWPFParagraph para) {
            this.text = run.getText(0);
            this.rPr = run.getCTR().isSetRPr() ? (CTRPr) run.getCTR().getRPr().copy() : null;
            this.pPr = para.getCTP().isSetPPr() ? (CTPPr) para.getCTP().getPPr().copy() : null;
        }

        public void applyToRun(XWPFParagraph paragraph) {
            XWPFRun newRun = paragraph.createRun();
            if (rPr != null) newRun.getCTR().setRPr(rPr);
            if (text != null) newRun.setText(text, 0);

            // 应用段落样式
            if (pPr != null && paragraph.getCTP() != null) {
                paragraph.getCTP().setPPr(pPr);
            }
        }
    }

    /**
     * 表格列参数类
     */
    private static class TableColumnParam {
        String name;
        int colspan = 1;

        public TableColumnParam(String name, int colspan) {
            this.name = name;
            this.colspan = colspan;
        }
    }

    /**
     * 为附件1-4插入分页符，确保每个附件单独一页
     */
    private static void insertAttachmentsPageBreaks(XWPFDocument doc) {
        List<XWPFParagraph> paragraphs = doc.getParagraphs();
        Pattern attachmentPattern = Pattern.compile("^附件\\d+\\s+");
        boolean firstAttachmentFound = false;
        boolean hasContentBeforeFirstAttachment = false; // 标记第一个附件前是否有内容

        for (int i = 0; i < paragraphs.size(); i++) {
            XWPFParagraph para = paragraphs.get(i);
            String text = para.getText().trim();

            if (attachmentPattern.matcher(text).find()) {
                // 首次找到附件1
                if (!firstAttachmentFound) {
                    firstAttachmentFound = true;
                    // 如果附件1不是文档的第一个元素，说明前面有内容
                    hasContentBeforeFirstAttachment = (i > 0);

                    // 若附件1前有内容且需要分页（根据实际情况调整）
                    if (hasContentBeforeFirstAttachment) {
                        // 在附件1标题前插入分页符，确保附件1从新页开始
                        XWPFParagraph pageBreakPara = doc.insertNewParagraph(para.getCTP().newCursor());
                        XWPFRun run = pageBreakPara.createRun();
                        run.addBreak(BreakType.PAGE);
                        i++; // 跳过新插入的分页符段落
                    }
                }
                // 非附件1（附件2-4），在标题前插入分页符
                else {
                    XWPFParagraph pageBreakPara = doc.insertNewParagraph(para.getCTP().newCursor());
                    XWPFRun run = pageBreakPara.createRun();
                    run.addBreak(BreakType.PAGE);
                    i++;
                }
            }
        }
    }
}